#ifndef _M_CONNECT_H_
#define _M_CONNECT_H_

#include "../mqthird/include/muduo/proto/dispatcher.h"
#include "../mqthird/include/muduo/proto/codec.h"
#include <muduo/net/TcpConnection.h>
#include "exchange.hpp"
#include "msgqueue.hpp"
#include "binding.hpp"
#include "message.hpp"
#include "virtualhost.hpp"
#include "routing.hpp"
#include "consumer.hpp"
#include "channel.hpp"

#include "../mqcommon/threadpool.hpp"
#include "../mqcommon/mqProto.pb.h"
#include "../mqcommon/mqlink.pb.h"
#include "../mqcommon/logger.hpp"
#include "../mqcommon/helper.hpp"

namespace MyRabbitMQ
{
    //连接类
    class Connection
    {
    public:
        using ptr = std::shared_ptr<Connection>;

        //连接初始化， 我们默认一个连接仅使用一台虚拟机
        Connection(const muduo::net::TcpConnectionPtr& conn,
        const ProtobufCodecPtr& codec,
        const threadpool::ptr& pool,
        const VirtualHost::ptr& host,
        const ConsumerManager::ptr& consumers)
        :m_channels(std::make_shared<ChannelManager>())
        ,m_conn(conn)
        ,m_codec(codec)
        ,m_threadpool(pool)
        ,m_host(host)
        ,m_consumers(consumers)
        {}

        //创建信道
        void openChannel(const openChannelRequestPtr& req)
        {
            //不存在则添加,存在不会进行处理
            m_channels->openChannel(req->channel_id(),m_conn,m_codec,m_threadpool,m_host,m_consumers);

            //进行响应
            return this->basicResponse(req->request_id(),req->channel_id(),true);
        }

        //关闭信道
        void closeChannel(const closeChannelRequestPtr& req)
        {
            //直接删除, 无论存在于否, 最终都会归于不存在
            m_channels->closeChannel(req->channel_id());

            //进行响应    
            return this->basicResponse(req->request_id(),req->channel_id(),true);
        }

        //获取特定信道
        Channel::ptr getChannel(const std::string& cid)
        {
            return m_channels->getChannnel(cid);  
        }

        private:
        ChannelManager::ptr m_channels; //信道管理句柄
        muduo::net::TcpConnectionPtr m_conn;    //信道所属tcp连接(顺便用作唯一性标识)
        ProtobufCodecPtr m_codec;                  //protobuf协议处理器, 处理序列化数据
        threadpool::ptr m_threadpool;                //线程工作池
        VirtualHost::ptr m_host;                //信道虚拟机管理句柄
        ConsumerManager::ptr m_consumers;       //信道消费者管理句柄

        //发送响应
        void basicResponse(const std::string& rid, const std::string& cid, bool isOk)
        {
            //构造响应
            protoMQ::basicCommonResponse resp;
            resp.set_response_id(rid);
            resp.set_channel_id(cid);
            resp.set_ok(isOk);

            //发送响应,通过协议处理器, 进行序列化, 并通过连接发送
            m_codec->send(m_conn,resp);
        }
    }; 

    class ConnectionManager
    {
    public:
        using ptr = std::shared_ptr<ConnectionManager>;
        
        ConnectionManager(){}

        //创建连接
        void createConnection(const muduo::net::TcpConnectionPtr& conn,
        const ProtobufCodecPtr& codec,
        const threadpool::ptr& pool,
        const VirtualHost::ptr& host,
        const ConsumerManager::ptr& consumers)
        {
            std::unique_lock<std::mutex>(m_mtx);
            //如果连接已经存在则无需创建
            if(m_connections.find(conn) != m_connections.end())
            {
                return;
            }

            auto ptr = std::make_shared<Connection>(conn,codec,pool,host,consumers);
            m_connections.insert(std::make_pair(conn,ptr));
        }

        //删除连接
        void removeConnection(const muduo::net::TcpConnectionPtr& conn)
        {
            std::unique_lock<std::mutex>(m_mtx);
            m_connections.erase(conn);
        }

        //获取连接
        Connection::ptr getConnection(const muduo::net::TcpConnectionPtr& conn)
        {
            std::unique_lock<std::mutex>(m_mtx);
            auto it = m_connections.find(conn);
            
            if(it == m_connections.end())
            {
                return Connection::ptr();
            }

            return it->second;
        }

    private:
        std::mutex m_mtx;
        std::unordered_map<muduo::net::TcpConnectionPtr,Connection::ptr> m_connections;
    };

};


#endif